# -*- coding:utf-8 -*-
"""
    异常进程检测
"""
from subprocess import Popen, PIPE

@config(alias="miner", enable=True)
def keyi_analysis(option):
    """查询挖矿进程、黑客工具、可疑进程名称"""

    suspicious = False
    if 1:
        p1 = Popen("ps -efwww 2>/dev/null", stdout=PIPE, shell=True)
        p2 = Popen("grep -E 'minerd|r00t|sqlmap|nmap|hydra|aircrack'", stdin=p1.stdout, stdout=PIPE, shell=True)
        p3 = Popen("grep -v 'grep'", stdin=p2.stdout, stdout=PIPE, shell=True)
        p4 = Popen("awk '{print $1\" \"$2\" \"$3\" \"$8}'", stdin=p3.stdout, stdout=PIPE, shell=True)
        process = p4.stdout.read().splitlines()
        if not len(process):
            monitoring_objects_num("miner") # 没有信息时，只有一个检测项。
            return suspicious
        for pro in process:
            pro = pro.decode()
            pro_info = pro.strip().split(' ', 3)
            monitoring_objects_num("miner") # 每个进程信息都可以添加一个检测项。
            cmd = " ".join(open('/proc/%s/cmdline'%pro_info[1]).read().split('\x00'))

            if isinstance(pro_info[1], str):
                save_result("可疑进程信息扫描", "pid: %s 进程名: %s ，解决方案 : kill %s #关闭恶意进程"%(pro_info[1], cmd, pro_info[1]), "h")
            else:
                save_result("可疑进程信息扫描", "pid: %s 进程名: %s ，解决方案 : kill %s #关闭恶意进程"%(pro_info[1].encode('gbk'), cmd, pro_info[1].encode('gbk')), "h")
            suspicious = True
        return suspicious
    else:
        return suspicious

@config(alias="exe", enable=True)
def exe_analysis(option):
    """判断进程的可执行文件是否具备恶意特征"""
    malice = False
    if 1:
        if not os.path.exists('/proc/'):
            monitoring_objects_num("exe") # 目录不存在时，只有一个检测项。
            return malice
        for file in os.listdir('/proc/'):
            monitoring_objects_num("exe") # 检测目录下面所有， 排查exe，所以在这里添加一个检测项。
            if file.isdigit():
                filepath = os.path.join('%s%s%s' % ('/proc/', file, '/exe'))
                if (not os.path.islink(filepath)) or (not os.path.exists(filepath)):
                    continue
                malware = analysis_file(filepath)
                if malware:
                    lnstr = os.readlink(filepath)
                    # save_result("exe程序进程安全扫描", lnstr, file, malware,
                    #               u'[1]ls -a %s [2]strings %s' % (filepath, filepath), u'风险',
                    #               programme=u'kill %s #关闭恶意进程' % lnstr)
                    save_result("exe程序进程安全扫描", "pid: %s 文件名: %s ，解决方案 : kill %s #关闭恶意进程"%(file, lnstr, file), "h")
                    malice = True
        return  malice
    else:
        return suspicious, malice

@config(alias="shell", enable=True)
def shell_analysis(option):
    """反弹shell类进程检测"""
    malice = False
    if 1:
        p1 = Popen("ps -efwww 2>/dev/null", stdout=PIPE, shell=True)
        p2 = Popen("grep -v 'grep'", stdin=p1.stdout, stdout=PIPE, shell=True)
        p3 = Popen("awk '{print $1\" \"$2\" \"$3\" \"$8\" \"$9\"  \"$10}'", stdin=p2.stdout, stdout=PIPE, shell=True)
        process = p3.stdout.read().splitlines()
        if not len(process):
            monitoring_objects_num("shell") # 没有反弹shell信息时，检测项加1.
            return False
        for pro in process:
            monitoring_objects_num("shell") # 每条信息都要进行检测，在这里每个信息都加一个检测项。
            pro = pro.decode()
            pro_info = pro.strip().split(' ', 3)
            if check_shell(pro_info[3]):
                # save_result("反弹shell类进程安全扫描", "%s 对应进程信息：%s ps -efwww 风险 kill %s #关闭恶意进程"%
                #             (pro_info[1], pro_info[3].replace("\n", ""),pro_info[1]), "h")
                # pro_info = pro_info.encode('gbk')
                save_result("反弹shell类进程安全扫描", "%s 对应进程信息：%s ps -efwww 风险 kill %s #关闭恶意进程"%
                            (pro_info[1].encode('gbk'), pro_info[3].replace("\n", "").encode('gbk'),pro_info[1].encode('gbk')), "h")
                malice = True
        return malice
    else:
        return malice

@config(alias="work", enable=True)
def work_analysis(option):
    """过滤cpu和内存使用的可疑问题"""

    suspicious = False
    if 1:
        p1 = Popen("ps aux 2>/dev/null", stdout=PIPE, shell=True)
        p2 = Popen('grep -v PID', stdin=p1.stdout, stdout=PIPE, shell=True)
        p3 = Popen('sort -rn -k3', stdin=p2.stdout, stdout=PIPE, shell=True)
        p4 = Popen('head', stdin=p3.stdout, stdout=PIPE, shell=True)
        p5 = Popen("awk '{print $1\" \"$2\" \"$3\" \"$4\" \"$11}'", stdin=p4.stdout, stdout=PIPE, shell=True)
        p6 = Popen(
            "grep -v -E 'systemd|rsyslogd|mysqld|redis|apache|nginx|mongodb|docker|memcached|tomcat|jboss|java|php|python'",
            stdin=p5.stdout, stdout=PIPE, shell=True)
        cpu_process = p6.stdout.read().splitlines()
        for pro in cpu_process:
            monitoring_objects_num("work") # 对每个进程信息进行cpu和mem的比较，在这里给每一条加上一个检测项，不知是否合适。
            pro = pro.decode()
            pro_info = pro.strip().split(' ', 4)
            # cpu使用超过标准
            if float(pro_info[2]) > cpu_value:
                if isinstance(pro_info[1], str):
                    save_result("CPU过载扫描", "%s进程使用CPU过大，对应进程信息: %s 风险 kill %s #关闭恶意进程"%
                            (pro_info[1], pro_info[4].replace("\n", ""), pro_info[1]), "m")
                else:
                    save_result("CPU过载扫描", "%s进程使用CPU过大，对应进程信息: %s 风险 kill %s #关闭恶意进程"%
                            (pro_info[1].encode('gbk'), pro_info[4].encode('gbk').replace("\n", ""), pro_info[1].encode('gbk')), "m")
                suspicious = True
            # 内存使用超过标准
            if float(pro_info[3]) > mem_value:
                if isinstance(pro_info[1], str):
                    save_result("内存过载扫描", "%s进程使用内存过大，对应进程信息：%s 风险, kill %s #关闭恶意进程"%
                            (pro_info[1], pro_info[4].replace("\n", ""), pro_info[1]), "m")
                else:
                    save_result("内存过载扫描", "%s进程使用内存过大，对应进程信息：%s 风险, kill %s #关闭恶意进程"%
                            (pro_info[1].encode('gbk'), pro_info[4].encode('gbk').replace("\n", ""), pro_info[1].encode('gbk')), "m")
                suspicious = True
        return suspicious
    else:
        return suspicious

@config(alias="hide_pro", enable=False)
def check_hide_pro(option):
    """检测隐藏进程"""
    malice = False

    if 1:
        # ps获取所有pid
        p1 = Popen("ps -ef 2>/dev/null", stdout=PIPE, shell=True)
        p2 = Popen("awk 'NR>1{print $2}'", stdin=p1.stdout, stdout=PIPE, shell=True)
        pid_process = p2.stdout.read().splitlines()

        # 所有/proc目录的pid
        pid_pro_file = []
        if not os.path.exists('/proc/'): return malice
        # for pid in range(1, int(cat("/proc/sys/kernel/pid_max") or 65535)):
        #     proc = '/proc/%d' % pid
        #     if os.path.exists(proc) and os.path.isdir(proc):
        #         pid_pro_file.append(str(pid))
        for file in os.listdir('/proc/'):
            if file.isdigit():
                pid_pro_file.append(file)
        hids_pid = list(set(pid_pro_file).difference(set([_.decode() for _ in pid_process])))
        # if len(hids_pid) > 10: return suspicious, malice
        for pid in hids_pid:
            log(pid, cat("/proc/{}/cmdline".format(pid)))
            save_result("隐藏进程扫描", "进程ID %s 隐藏了进程信息，未出现在进程列表中"%(pid), "m")
            # malice_result(self.name, u'隐藏进程扫描', '', pid, u'进程ID %s 隐藏了进程信息，未出现在进程列表中' % pid,
            #               u"[1] cat /proc/$$/mountinfo [2] umount /proc/%s [3]ps -ef |grep %s" % (pid, pid), u'风险',
            #               umount /proc/%s & kill %s #关闭隐藏进程并结束进程' % (pid, pid))
            malice = True
        return malice
    else:
        return malice
